// =============================================================
// CDiscoveryService
// ---------------------------------------
// Author : Woo-Hyun Kim
// Email : woorung@icu.ac.kr or woorung@nhncorp.com
// Date : Oct. 8, 2007
// =============================================================
#include "CDiscoveryService.h"

CDiscoveryService::CDiscoveryService(char *name) : CService(name) 
{
	service_space = new CSpace(CUBE_SERVICE_DISCOVERY);

	purge_thread = NULL;

	// run only once when an instance is initialized
	purge();
}

CDiscoveryService::CDiscoveryService(const CDiscoveryService &rhs) : CService(rhs)
{
/*
	this->setName((char *)rhs.getName());
	this->instance((char *)rhs.instance());
*/

	service_space = rhs.service_space;
	purge_thread = rhs.purge_thread;
}

CDiscoveryService::~CDiscoveryService() 
{
	//delete service_space;
}

CDiscoveryService *CDiscoveryService::clone() const 
{
	return new CDiscoveryService(*this);
}

CDiscoveryService &CDiscoveryService::operator=(const CDiscoveryService &rhs) 
{
	this->setName((char *)rhs.getName());
	this->instance((char *)rhs.instance());

	service_space = rhs.service_space;
	purge_thread = rhs.purge_thread;

	return *this;
}

void CDiscoveryService::purge() 
{
	if(purge_thread==NULL) {
#ifdef DEBUG
		cout << "######################################### only once ##########" << endl;
#endif
		purge_thread = new CPurgeThread("space.purge.thread");
		purge_thread->setSpace(service_space);

		purge_thread->start();
	}
}

int CDiscoveryService::registry(CObjectArray *&objs, CObjectArray *&pobjs)
{
	for(int i=1;i<objs->__size;i++) {
		char *name = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getName();
		char *ip = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getIP();
		int port = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getPort();
		time_t ttl = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getTTL();

		float cpu = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getCPU();
		float load = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getLoad();

		CServiceInfo sinfo(name, ip, port, ttl);
		sinfo.setStatus(cpu, load);
		service_space->write(&sinfo, &sinfo, ttl);
	}

#ifdef DEBUG
	vector< CSmartTemplate<CObject> > all;
	all = service_space->read(NULL, service_space->size(), all);
	cout << "-------------- write : all objects ---------------" << endl;
	cout << "size = " << all.size() << endl;
	for(int i=0;i<all.size();i++) {
		char *name = dynamic_cast<CServiceInfo &>(*all[i]).getName();
		char *ip = dynamic_cast<CServiceInfo &>(*all[i]).getIP();
		int port =dynamic_cast<CServiceInfo &>(*all[i]).getPort(); 
		time_t ttl = dynamic_cast<CServiceInfo &>(*all[i]).getTTL();

		cout << "service name = " << name << endl;
		cout << "ip = " << ((ip!=NULL)?ip:"null") << endl;
		cout << "port = " << port << endl;
		cout << "ttl = " << ttl << endl;

		float cpu = dynamic_cast<CServiceInfo &>(*all[i]).getCPU();
		float load = dynamic_cast<CServiceInfo &>(*all[i]).getLoad();

		cout << "cpu = " << cpu << endl;
		cout << "load = " << load << endl;
	}
	cout << "------------------------------------------" << endl << endl;
#endif

	pobjs->__size = 1;
	pobjs->__ptr = (cube__CObject **)soap_malloc(soap, (pobjs->__size)*sizeof(*pobjs->__ptr));

	pobjs->__ptr[0] = (cube__CKeyValue *)soap_new_cube__CKeyValue(soap, -1);
	char size[100];
	sprintf(size, "%d", service_space->size());
	dynamic_cast<cube__CKeyValue *>(pobjs->__ptr[0])->setKey(CUBE_DISCOVERY_COUNT);
	dynamic_cast<cube__CKeyValue *>(pobjs->__ptr[0])->setValue(size);
}

int CDiscoveryService::discovery(CObjectArray *&objs, CObjectArray *&pobjs)
{
	vector< CSmartTemplate<CObject> > found;

	for(int i=1;i<objs->__size;i++) {
		if(objs->__ptr[i]!=NULL) {
			char *name = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getName();
			char *ip = NULL;
			int port = -1;

			CServiceInfo sinfo(name, ip, port);
			//found = service_space->read(&sinfo, service_space->size(), found);
			found = service_space->readIfExists(&sinfo, service_space->size(), found);

#ifdef DEBUG
			cout << "-------------- found services ---------------" << endl;
			cout << "size = " << found.size() << endl;
			for(int i=0;i<found.size();i++) {
				char *name = dynamic_cast<CServiceInfo &>(*found[i]).getName();
				char *iname = dynamic_cast<CServiceInfo &>(*found[i]).instance();
				char *ip = dynamic_cast<CServiceInfo &>(*found[i]).getIP();
				int port =dynamic_cast<CServiceInfo &>(*found[i]).getPort(); 
				time_t ttl = dynamic_cast<CServiceInfo &>(*found[i]).getTTL();

				float cpu = dynamic_cast<CServiceInfo &>(*found[i]).getCPU();
				float load = dynamic_cast<CServiceInfo &>(*found[i]).getLoad();

				cout << "service name = " << name << endl;
				cout << "service instance = " << iname << endl;
				cout << "ip = " << ((ip!=NULL)?ip:"null") << endl;
				cout << "port = " << port << endl;
				cout << "ttl = " << ttl << endl;
				cout << "cpu = " << cpu << endl;
				cout << "load = " << load << endl;
			}
			cout << "------------------------------------------" << endl << endl;
#endif
		}
		else {
			//found = service_space->read(NULL, service_space->size(), found);
			found = service_space->readIfExists(NULL, service_space->size(), found);

#ifdef DEBUG
			cout << "-------------- found services ---------------" << endl;
			cout << "size = " << found.size() << endl;
			for(int i=0;i<found.size();i++) {
				char *name = dynamic_cast<CServiceInfo &>(*found[i]).getName();
				char *iname = dynamic_cast<CServiceInfo &>(*found[i]).instance();
				char *ip = dynamic_cast<CServiceInfo &>(*found[i]).getIP();
				int port =dynamic_cast<CServiceInfo &>(*found[i]).getPort(); 
				time_t ttl = dynamic_cast<CServiceInfo &>(*found[i]).getTTL();

				float cpu = dynamic_cast<CServiceInfo &>(*found[i]).getCPU();
				float load = dynamic_cast<CServiceInfo &>(*found[i]).getLoad();

				cout << "service name = " << name << endl;
				cout << "service instance = " << iname << endl;
				cout << "ip = " << ((ip!=NULL)?ip:"null") << endl;
				cout << "port = " << port << endl;
				cout << "ttl = " << ttl << endl;
				cout << "cpu = " << cpu << endl;
				cout << "load = " << load << endl;
			}
			cout << "------------------------------------------" << endl << endl;
#endif
			break;
		}
	}

	pobjs->__size = found.size();
	pobjs->__ptr = (cube__CObject **)soap_malloc(soap, (pobjs->__size)*sizeof(*pobjs->__ptr));
	
	for(int i=0;i<found.size();i++) {
		CServiceInfo &that = dynamic_cast<CServiceInfo &>(*found[i]);
		pobjs->__ptr[i] = (cube__CServiceInfo *)soap_new_cube__CServiceInfo(soap, -1);
		dynamic_cast<cube__CServiceInfo *>(pobjs->__ptr[i])->set(that.getName(), that.getIP(), that.getPort(), that.getTTL());
		dynamic_cast<cube__CServiceInfo *>(pobjs->__ptr[i])->setStatus(that.getCPU(), that.getLoad());
#ifdef DEBUG
		cout << "-------------- return services ---------------" << endl;
		cout << "cpu = " << that.getCPU() << ", " << dynamic_cast<cube__CServiceInfo *>(pobjs->__ptr[i])->getCPU() << endl;
		cout << "load = " << that.getLoad() << ", " << dynamic_cast<cube__CServiceInfo *>(pobjs->__ptr[i])->getLoad() << endl;
#endif
	}
}

void CDiscoveryService::run(cube__CObject *in, struct cube__invokeResponse &res) 
{
	CObjectArray *objs = dynamic_cast<CObjectArray *>(in);
	if(objs==NULL) return;

#ifdef DEBUG
	cout << "command = " << dynamic_cast<cube__CKeyValue *>(objs->__ptr[0])->getValue() << endl;

	for(int i=1;i<objs->__size;i++) {
		char *name = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getName();
		char *ip = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getIP();
		int port = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getPort();
		time_t ttl = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getTTL();

		float cpu = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getCPU();
		float load = dynamic_cast<cube__CServiceInfo *>(objs->__ptr[i])->getLoad();

		cout << "service name = " << name << endl;
		cout << "ip = " << ((ip!=NULL)?ip:"null") << endl;
		cout << "port = " << port << endl;
		cout << "ttl = " << ttl << endl;
		cout << "cpu = " << cpu << endl;
		cout << "load = " << load << endl;
	}
	cout << endl;
#endif

	char *cmd = dynamic_cast<cube__CKeyValue *>(objs->__ptr[0])->getValue();


#ifdef DEBUG
	cout << "### command = " << cmd << endl;
#endif

	CObjectArray *pobjs = (CObjectArray *)soap_new_CObjectArray(soap, -1);

	// registry
	if(objs->__size>1&&strcmp(cmd,CUBE_DISCOVERY_REGISTRY)==0) registry(objs,pobjs);
	// discovery
	else if(objs->__size>1&&strcmp(cmd,CUBE_DISCOVERY_DISCOVERY)==0) discovery(objs,pobjs);
	else {
		pobjs->__size = 0;
		pobjs->__ptr = NULL;
	}


	res.out = pobjs;
}
